package me.boot.db.mybatis.interceptor.tenant;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import me.boot.common.context.ContextUtil;
import me.boot.db.mybatis.datasource.DynamicDataSourceService;
import me.boot.db.mybatis.interceptor.TenantInterceptor;
import me.boot.db.mybatis.propertites.TenantMode;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

/**
 * DATASOURCE 模式插件
 */
@Slf4j
@Intercepts({
        //type指定代理的是那个对象，method指定代理Executor中的那个方法,args指定Executor中的query方法都有哪些参数对象
        //由于Executor中有两个query，因此需要两个@Signature
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class TenantDatasourceModeInterceptor implements Interceptor, TenantInterceptor {

    @Lazy
    @Autowired
    DynamicDataSourceService dynamicDataSourceService;

    @Override
    public TenantMode getTenantMode() {
        return TenantMode.DATASOURCE;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        String tenantId = ContextUtil.getTenantId();
        if (StrUtil.isNotEmpty(tenantId)) {
            return dynamicDataSourceService.holdTenant(tenantId,
                    (dsName) -> {
                        try {
                            log.debug("切换租户数据源:{} ", dsName);
                            return invocation.proceed();
                        } catch (Exception e) {
                            log.error("租户id={} 数据源={} 发生异常：\n{}", tenantId, dsName, e.getMessage());
                            e.printStackTrace();
                            return null;
                        }
                    });
        } else {
            return invocation.proceed();
        }
    }
}
